# -*- coding: utf-8 -*-
import pygame
import random

# 设置窗口大小，获取Surface
SCREEN_WIDTH = 640
SCREEN_HEIGHT = 480
BLOCK_SIZE = 20
COLOR_GRAY = (150, 150, 150)
COLOR_WHITE = (255, 255, 255)
COLOR_BLUE = (0, 0, 255)
# 身体方向字典
DIRECTION_DICT = {
    pygame.K_UP: (0, -BLOCK_SIZE),  # 上
    pygame.K_RIGHT: (BLOCK_SIZE, 0),  # 右
    pygame.K_DOWN: (0, BLOCK_SIZE),  # 下
    pygame.K_LEFT: (-BLOCK_SIZE, 0),  # 左
}
#蛇头方向字典
HEAD_DICT = {
    pygame.K_RIGHT: 90,
    pygame.K_DOWN: 0,
    pygame.K_UP: 180,
    pygame.K_LEFT: 270,
}


class Snake:

    def __init__(self):
        self.direction = pygame.K_RIGHT
        self.snake_body = [
            pygame.Rect(5 * BLOCK_SIZE, 3 * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE),
            pygame.Rect(4 * BLOCK_SIZE, 3 * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE),
            pygame.Rect(3 * BLOCK_SIZE, 3 * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE),
            pygame.Rect(3 * BLOCK_SIZE, 3 * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE),
            pygame.Rect(3 * BLOCK_SIZE, 3 * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE),
        ]
        head_image = pygame.image.load('res/head-red.png')
        # 对图片大小缩放
        self.snake_head_image = pygame.transform.scale(head_image, (BLOCK_SIZE, BLOCK_SIZE))

    def draw(self, screen):
        # 绘制蛇身体
        for node in self.snake_body[1:]:
            pygame.draw.rect(screen, COLOR_WHITE, node, border_radius=3)
        # 绘制蛇头
        head: pygame.Rect = self.snake_body[0]
        head_image = pygame.transform.rotate(self.snake_head_image, HEAD_DICT[self.direction])
        screen.blit(head_image, (head.x, head.y))

    def set_direcation(self, new_direction):
        # 禁止水平或竖直方向直接变换
        # 不能原地掉头（水平方向）
        LR = (pygame.K_RIGHT, pygame.K_LEFT,)
        if self.direction in LR and new_direction in LR:
            return False

        # 不能原地掉头（垂直方向）
        UD = (pygame.K_UP, pygame.K_DOWN,)
        if self.direction in UD and new_direction in UD:
            return False

        self.direction = new_direction

    def move(self):
        # 蛇头往前进方向复制一份移动一格，把蛇尾删除
        new_node = self.snake_body[0].copy()
        # 0上,1右,2下,3右
        new_move = DIRECTION_DICT[self.direction]  # 字典里对应4种方向
        new_node.x += new_move[0]  # 键值中元素1对应的是X方向
        new_node.y += new_move[1]  # 键值中元素2对应的是Y方向
        # 新的蛇头放在最前面
        self.snake_body.insert(0, new_node)
        # 蛇尾移除
        self.snake_body.pop()  # 索引不传参，默认移除最后一个

    def grow(self):
        # 蛇尾复制一份，添加新的节点到尾部
        new_node = self.snake_body[-1].copy()
        self.snake_body.append(new_node)
class Food:
    def __init__(self, node):
        self.node = node

    def draw(self, screen):
        pygame.draw.rect(screen, COLOR_BLUE, self.node, border_radius=3)
    @staticmethod
    def gen_food_position(snake: Snake) -> pygame.Rect:
        while True:
            # 根据屏幕宽高，蛇身信息生成新的食物的X,Y坐标
            x = random.randint(0, SCREEN_WIDTH // BLOCK_SIZE - 1)  # 0,1,2...31
            y = random.randint(0, SCREEN_HEIGHT // BLOCK_SIZE - 1)  # 0,1,2...23
            new_food_node = pygame.Rect(x * BLOCK_SIZE, y * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE)
            if new_food_node not in snake.snake_body:
                return new_food_node


class Game:

    def __init__(self) -> None:

        # 设置窗口大小
        self.screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))

        # 设置标题
        pygame.display.set_caption("贪吃蛇V1.0")

        # 设置图标
        icon = pygame.image.load('res/icon.png')
        pygame.display.set_icon(icon)

        # 加载背景图(缩放)
        bg_image = pygame.image.load('res/bg.png')
        self.bg_image = pygame.transform.scale(bg_image, (SCREEN_WIDTH, SCREEN_HEIGHT))

    def start(self):

        # clock
        clock = pygame.time.Clock()
        snake = Snake()

        food = Food(Food.gen_food_position(snake))
        while True:
            # 处理事件，获取用户的输入事件
            event_list = pygame.event.get()
            # 解析处理事件
            for event in event_list:
                if event.type == pygame.QUIT:
                    print("用户退出")
                    exit(0)
                elif event.type == pygame.KEYDOWN:
                    print("按键被按下：", event.key)
                    # 上、下、左、右、空格
                    if event.key == pygame.K_UP:
                        print('向上')
                        snake.set_direcation(pygame.K_UP)
                    elif event.key == pygame.K_RIGHT:
                        print('向右')
                        snake.set_direcation(pygame.K_RIGHT)
                    elif event.key == pygame.K_DOWN:
                        print('向下')
                        snake.set_direcation(pygame.K_DOWN)
                    elif event.key == pygame.K_LEFT:
                        print('向左')
                        snake.set_direcation(pygame.K_LEFT)
                    elif event.key == pygame.K_SPACE:
                        print('空格')
                    elif event.key == pygame.K_ESCAPE:
                        pygame.display.quit()
                        exit(0)
            # 处理游戏逻辑-----------------------
            snake.move()
            # 遇到食物吃掉食物身体长一节
            if snake.snake_body[0] == food.node:
                # 吃掉食物，刷新食物
                food = Food(Food.gen_food_position(snake))
                # 蛇身长一节
                snake.grow()

            # 渲染界面---------------------------
            # 背景图
            self.screen.blit(self.bg_image, (0, 0))
            # 网格线
            # pygame.draw.line(screen,COLOR_GRAY,(0,0),(300,100 ))
            # 绘制所有横线，h=480//BLOCK_SIZE =24
            for y in range(0, SCREEN_HEIGHT, BLOCK_SIZE):
                start = (0, y)
                end = (SCREEN_WIDTH, y)
                pygame.draw.line(self.screen, COLOR_GRAY, start, end)
            # 绘制所有竖线，w = 640/BLOCK_SIZE = 32
            for w in range(0, SCREEN_WIDTH, BLOCK_SIZE):
                start = (w, 0)
                end = (w, SCREEN_HEIGHT)
                pygame.draw.line(self.screen, COLOR_GRAY, start, end)
            # 绘制蛇身
            snake.draw(self.screen)
            # 绘制食物
            food.draw(self.screen)

            pygame.display.flip()  # 执行最终渲染
            # 计算FPS,控制渲染速度
            clock.tick(10)


game = Game()
game.start()
